home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / src / vmake / gadgets.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-09  |  39.7 KB  |  1,091 lines

  1. /*
  2.  *    (c)Copyright 1992-1997 Obvious Implementations Corp.  Redistribution and
  3.  *    use is allowed under the terms of the DICE-LICENSE FILE,
  4.  *    DICE-LICENSE.TXT.
  5.  */
  6. #include "vmake.h"
  7.  
  8. Prototype int  init_gadgets(void);
  9. Prototype void free_gadget(struct Gadget *gadget);
  10. Prototype void free_gadlist(struct GADLIST *gadlist);
  11. Prototype struct Gadget *create_gadget(struct GADLIST *gadlist,struct G_OBJECT *object,int ulx, int uly,int width);
  12. Prototype void setup_string_gadget(struct Gadget *gad,int base);
  13. Prototype struct Gadget *setup_cycle_gadget(struct Gadget *gad,struct IntuiText *itext,struct G_VALUE *val);
  14. Prototype void reset_list_object(struct G_LIST *list,int active);
  15. Prototype int  setup_list_object(struct GADLIST *gadlist,struct Gadget *gad);
  16. Prototype struct GADLIST *layout_gadgets(struct G_OBJECT *objlist, int ulx, int uly, int width);
  17. Prototype struct Border *build_border(int width, int height, int mode);
  18. Prototype int  init_gad_sizes(int swidth, int sheight, int resize);
  19. Prototype int  create_borders(void);
  20. Prototype int  recalc_group_sizes(struct G_OBJECT *objlist, int *titsize, int *cycsize);
  21. Prototype int  text_width(char *str);
  22.  
  23. /***********************************************************************************
  24.  * Procedure: init_gadgets
  25.  * Synopsis:  rc = init_gadgets();
  26.  * Purpose:   Set up all the base system gadgets for the window.  This includes all
  27.  *            The user defined gadgets as well as the three buttons on the bottom
  28.  ***********************************************************************************/
  29. int init_gadgets()
  30. {
  31.    struct Gadget *gad;
  32.    struct IntuiText *itext;
  33.    int ulx, uly;
  34.    int i;
  35.    int buttons;
  36.  
  37.    global.gadlist = layout_gadgets(global.objects,
  38.                                     global.ri.WindowLeft,
  39.                                     global.ri.WindowTitle,
  40.                                     global.cycsize+global.titsize
  41.                                     );
  42.    if (global.gadlist == NULL) return(1);
  43.    ulx = global.ri.WindowLeft;
  44.    uly = global.height - global.ri.WindowBottom - global.iheight;
  45.  
  46.    buttons = (global.width - (global.ri.WindowLeft + global.ri.WindowRight)) / BUTTON_WIDTH;
  47.    if (buttons > 5) buttons = 5;
  48.  
  49.    for(i = 0; i < buttons; i++)
  50.    {
  51.       global.button[i].base.class = CLASS_BUTTON;
  52.       global.button[i].base.state = i; /* Note that these values correspond to */
  53.                                    /* the BUTTON_xxx equates               */
  54.  
  55.       gad = create_gadget(NULL, (struct G_OBJECT *)(global.button+i),
  56.                                 ulx, uly, BUTTON_WIDTH);
  57.  
  58.       if (gad == NULL) return(1);
  59.       gad->GadgetRender = build_border(BUTTON_WIDTH,
  60.                                        global.iheight, MODE_OUT);
  61.  
  62.       itext = gad->GadgetText;
  63.       itext->LeftEdge += (BUTTON_WIDTH - IntuiTextLength(itext))/2;
  64.  
  65.       gad->NextGadget = global.gadlist->gadgets;
  66.       global.gadlist->gadgets = gad;
  67.       global.gadlist->count++;
  68.  
  69.       gad->GadgetType = BOOLGADGET;
  70.  
  71.       ulx += (global.width - (global.ri.WindowLeft  +
  72.                                global.ri.WindowRight +
  73.                                (buttons*BUTTON_WIDTH)
  74.                               )
  75.              ) / (buttons-1) + BUTTON_WIDTH;
  76.    }
  77.  
  78.    return(0);
  79. }
  80. /***********************************************************************************
  81.  * Procedure: free_gadget
  82.  * Synopsis:  free_gadget(gadget)
  83.  * Purpose:   Free up all memory associated with a gadget
  84.  ***********************************************************************************/
  85. void free_gadget(struct Gadget *gadget)
  86. {
  87.    struct G_OBJECT *obj;
  88.  
  89.    if (gadget)
  90.    {
  91.       obj = (struct G_OBJECT *)(gadget->UserData);
  92.  
  93.       obj->gadget = NULL;
  94.  
  95.       if (obj->class == CLASS_STRING)
  96.       {
  97.          /* We need to free the border structure also */
  98.       }
  99.       free_mem(gadget, sizeof(struct Gadget)+sizeof(struct IntuiText));
  100.    }
  101. }
  102.  
  103. /***********************************************************************************
  104.  * Procedure: free_gadlist
  105.  * Synopsis:  free_gadlist(gadlist)
  106.  * Purpose:   Free up all memory associated with a gadget list created by
  107.  *            layout_gadgets
  108.  ***********************************************************************************/
  109. void free_gadlist(struct GADLIST *gadlist)
  110. {
  111.    struct Gadget *gad, *nextgad;
  112.    struct G_CYCLE *cyc;
  113.    struct G_STRING *str;
  114.  
  115.    if (!gadlist) /* never allocated or already freed */
  116.       return;
  117.  
  118.    for(gad = gadlist->gadgets; gad && gadlist->count; gad = nextgad, gadlist->count--)
  119.    {
  120.       nextgad = gad->NextGadget;
  121.       cyc = (struct G_CYCLE *)gad->UserData;
  122.  
  123.       if ((cyc->base.class & CLASS_MASK) == CLASS_CYCLE)
  124.       {
  125.          /* If there is a string gadget currently in the cycle gadget, we need */
  126.          /* to free it up                                                      */
  127.          if ((str = cyc->curval->string) != NULL)
  128.          {
  129.             free_gadget(str->base.gadget);
  130.          }
  131.       }
  132.       free_gadget(gad);
  133.    }
  134.  
  135.    free_mem(gadlist, sizeof(struct GADLIST));
  136. }
  137.  
  138. /***********************************************************************************
  139.  * Procedure: create_gadget
  140.  * Synopsis:  Gadget = create_gadget(gadlist, object, ulx, uly, width)
  141.  * Purpose:   Create all the appropriate gadgetry and image structures for a list
  142.  *            of gadgets.
  143.  ***********************************************************************************/
  144. struct Gadget *create_gadget(struct GADLIST *gadlist,
  145.                              struct G_OBJECT *object,
  146.                              int ulx, int uly,
  147.                              int width
  148.                             )
  149. {
  150.    struct Gadget *gad;
  151.    struct IntuiText *itext;
  152.  
  153.  
  154.    /* Create a gadget structure and an associated intuitext structure to be */
  155.    /* Layed out on the screen                                               */
  156.    gad = (struct Gadget *)get_mem(sizeof(struct Gadget)+sizeof(struct IntuiText));
  157.    if (gad)
  158.    {
  159.       itext = (struct IntuiText *)(gad+1);
  160.  
  161.       gad->LeftEdge    = ulx;
  162.       gad->TopEdge     = uly;
  163.       gad->Width       = width;
  164.       gad->Height      = global.iheight;
  165.       gad->Flags       = GADGHCOMP;
  166.       gad->Activation  = RELVERIFY;
  167.       gad->GadgetText  = itext;
  168.       gad->UserData    = (APTR)object;
  169.       gad->GadgetID    = object->class; /* set both class and subclass */
  170.       gad->GadgetType   = BOOLGADGET;
  171.  
  172.       object->gadget      = gad;
  173.  
  174.       /* Now we fill in the Intuitext structure */
  175.       itext->FrontPen  = 1;
  176.       itext->BackPen   = 0;
  177.       itext->DrawMode  = JAM1;
  178.       itext->LeftEdge  = 0;
  179.       itext->TopEdge   = (global.iheight - global.ri.FontSize) / 2;
  180.       itext->ITextFont = &global.ri.TextAttr;
  181.       itext->IText     = object->title;
  182.       itext->NextText  = NULL;
  183.  
  184.       if (gadlist)
  185.       {
  186.          gad->NextGadget = gadlist->gadgets;
  187.          gadlist->gadgets = gad;
  188.          gadlist->count++;
  189.       }
  190.    }
  191.  
  192.    return(gad);
  193. }
  194.  
  195. /***********************************************************************************
  196.  * Procedure: setup_string_gadget
  197.  * Synopsis:  setup_string_gadget(gad, string, ulx, uly, width, base)
  198.  * Purpose:   Create all the appropriate gadgetry and image structures for a list
  199.  *            of gadgets.
  200.  ***********************************************************************************/
  201. void setup_string_gadget(struct Gadget *gad,
  202.                          int base
  203.                         )
  204. {
  205.    int wraps;
  206.    int i;
  207.    struct Border *border;
  208.    struct StringInfo *si;
  209.    int sluff;
  210.  
  211.    if (gad == NULL) return;
  212.  
  213.    wraps = (base == CLASS_STRING) ? 2 : 1;
  214.  
  215.    gad->LeftEdge += VBAR*wraps;
  216.    gad->TopEdge  += DHBAR;
  217.    gad->Width    -= DVBAR*wraps;
  218.    gad->Height   -= 2*DHBAR;
  219.  
  220.    sluff = (gad->Height - global.ri.FontSize);
  221.    if (sluff < 0) sluff = 0;
  222.    gad->Height  = global.ri.FontSize;
  223.    gad->TopEdge += sluff / 2;
  224.    if (gad->GadgetText)
  225.    {
  226.       gad->GadgetText->TopEdge -= (DHBAR+sluff);
  227.       gad->GadgetText->LeftEdge -= VBAR*wraps;
  228.    }
  229.  
  230.    if ((base == CLASS_LIST)   ||
  231.        (base == CLASS_STRING) ||
  232.        (base == CLASS_CYCLE))
  233.    {
  234.       for(i=wraps; i > 0; i--)
  235.       {
  236.          /* We need to put a border around the gadget. */
  237.          /* For some string gadgets, we only need a single border */
  238.          /* We can tell this by the base type */
  239.          border = build_border(gad->Width+4*i, gad->Height + sluff + 2*i,
  240.                                (i == 1) ? MODE_IN : MODE_OUT);
  241.          if (border != NULL)
  242.          {
  243.             border->NextBorder->LeftEdge = border->LeftEdge = -2*i;
  244.             border->NextBorder->TopEdge  = border->TopEdge  = -1*i - (sluff/2);
  245.             border->NextBorder->NextBorder = gad->GadgetRender;
  246.             gad->GadgetRender = border;
  247.          }
  248.       }
  249.    }
  250.  
  251.    /* Lastly, we need to setup up the SpecialInfo structure for the string gadget */
  252.    /* If for some reason this fails, we will turn it into a button gadget         */
  253.    si = (struct StringInfo *)get_mem(sizeof(struct StringInfo));
  254.    if (si != NULL)
  255.    {
  256.       gad->SpecialInfo = (APTR)si;
  257.       gad->GadgetType = STRGADGET;
  258.       si->Buffer = ((struct G_STRING *)(gad->UserData))->buf;
  259.       si->MaxChars = MAX_STRING;
  260.    }
  261.    else
  262.       gad->GadgetType = BOOLGADGET;
  263. }
  264.  
  265.  
  266. /***********************************************************************************
  267.  * Procedure: setup_cycle_gadget
  268.  * Synopsis:  gadget = setup_cycle_gadget(gadget, value)
  269.  * Purpose:   Create any subtending string gadgets and correctly position any
  270.  *            cycle value text
  271.  ***********************************************************************************/
  272. struct Gadget *setup_cycle_gadget(struct Gadget *gad,
  273.                                   struct IntuiText *itext,
  274.                                   struct G_VALUE *val
  275.                                  )
  276. {
  277.    struct Gadget *strgad;
  278.    int ilen;
  279.  
  280.    ilen = IntuiTextLength(itext);
  281.  
  282.    if (val->string)
  283.    {
  284.       int x, width;
  285.  
  286.       itext->LeftEdge = CYC_ICON_WIDTH + 2;
  287.       /* We need to create a string gadget to get the input text from */
  288.  
  289.       x = itext->LeftEdge + ilen;
  290.       width = gad->Width - x - 2;
  291.  
  292.       /* Now, create a string gadget and border to put around the gadget */
  293.       strgad = create_gadget(NULL, (struct G_OBJECT *)val->string,
  294.                                        gad->LeftEdge+x, gad->TopEdge, width);
  295.       if (strgad)
  296.       {
  297.          setup_string_gadget(strgad, CLASS_CYCLE);
  298.       }
  299.    }
  300.    else
  301.    {
  302.       strgad = NULL;
  303.       itext->LeftEdge  = (CYC_ICON_WIDTH + gad->Width - ilen) / 2;
  304.    }
  305.    return(strgad);
  306. }
  307. /***********************************************************************************
  308.  * Procedure: reset_list_object
  309.  * Synopsis:  void reset_list_object(list,active);
  310.  * Purpose:   Initialize all the appropriate text pointers for a list gadget
  311.  ***********************************************************************************/
  312. void reset_list_object(struct G_LIST *list,
  313.                        int active
  314.                       )
  315. {
  316.    struct G_ENTRY *ent;
  317.    int i;
  318.  
  319.    ent = list->top;
  320.  
  321.    /* Run through all the entries visible on the screen and for each */
  322.    /* one that is displayed, mark the gadget as selectable.          */
  323.    for(i = 0; i < global.listsize; i++)
  324.    {
  325. /*
  326.       list->btngad[i]->Flags  = (list->btngad[i]->Flags & ~GADGHIGHBITS) |
  327.                                 GADGHNONE;
  328. */
  329.       list->btngad[i]->Flags  = (list->btngad[i]->Flags & ~GADGHIGHBITS) |
  330.                                 GADGHCOMP;
  331.       list->btngad[i]->Height = global.eheight;
  332.       list->strgad[i]->GadgetRender = NULL;
  333.       ((struct StringInfo *)list->strgad[i]->SpecialInfo)->Buffer
  334.               = global.defbuf;  /* because RefreshGlist might write to it... */
  335. /*      global.defbuf[0] = 0; */    /* want this to work like a null string */
  336.  
  337.       /* Is there an entry corresponding to this position on the screen? */
  338.       if (ent)
  339.       {
  340.          /* Certainly is an entry, is it where they want a string gadget ? */
  341.          if (i == active)
  342.          {
  343.             /* Yes, shrink the gadget out of existence so that it doesn't  */
  344.             /* appear on the screen.                                       */
  345. /* prevent mouse activation ?
  346.             list->btngad[i]->Height = 1;
  347. */
  348.             list->strgad[i]->GadgetRender = list->sborder;
  349.          }
  350. /*         else */
  351.          {
  352.             list->btngad[i]->Flags = (list->btngad[i]->Flags & ~GADGHIGHBITS) |
  353.                                      GADGHCOMP;
  354.          }
  355.  
  356.          ((struct StringInfo *)
  357.           list->strgad[i]->SpecialInfo)->Buffer = ent->buf;
  358.          ent = (struct G_ENTRY *)ent->base.next;
  359.       }
  360.    }
  361. }
  362.  
  363. /***********************************************************************************
  364.  * Procedure: setup_list_object
  365.  * Synopsis:  ulx = setup_list_object(gadlist, gadget)
  366.  * Purpose:   Create all the appropriate gadgetry and image structures for a list
  367.  *            object
  368.  ***********************************************************************************/
  369. int setup_list_object(struct GADLIST *gadlist,
  370.                       struct Gadget *gad
  371.                      )
  372. {
  373.    int ulx, uly, alen, dlen, ilen;
  374.    struct G_LIST *list;
  375.    int i;
  376.    char *savetitle;
  377.    struct Gadget *slider, *dngad, *upgad, *addgad, *delgad;
  378.    struct PropInfo *pi;
  379.  
  380. #define ARR_HEIGHT  (7+DHBAR)
  381. #define PROP_WIDTH  (14+DVBAR)
  382.  
  383.    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  384.    /* A list object consists of 8 separate gadgets arranged as below*/
  385.    /* 1: Boolean gadgets that overlay string gadgets.  When the     */
  386.    /* 2:   string gadget is to be active, the height of the boolean */
  387.    /* 3:   gadget is set to 1 exposing the string gadget.           */
  388.    /* 4: A slider gadget to allow positioning in the list           */
  389.    /* 5: An up arrow gadget for moving up one item in the list      */
  390.    /* 6: A Down arrow gadget for moving down one item in the list   */
  391.    /* 7: A NEW gadget for creating an entry in front of current item*/
  392.    /* 8: A DEL gadget for removing the current item from the list.  */
  393.    /*                                                               */
  394.    /*                                                               */
  395.    /*  TITLE TEXT                                                   */
  396.    /* ............................................}+---+            */
  397.    /* ::+---------------------------------------+}}|4  |            */
  398.    /* ::|1                                      |}}|   |            */
  399.    /* ::| I T E M 1                             |}}|   |            */
  400.    /* ::+---------------------------------------+}}| _ |+-------+   */
  401.    /* ::+---------------------------------------+}}|[_]||7      |   */
  402.    /* ::|2                                      |}}|   || N E W |   */
  403.    /* ::| I T E M 2                             |}}+---+|       |   */
  404.    /* ::+---------------------------------------+}}|5^ |+-------+   */
  405.    /* ::+---------------------------------------+}}|/ \|+-------+   */
  406.    /* ::|3                                      |}}+---+|8      |   */
  407.    /* ::| I T E M 3                             |}}|\ /|| D E L |   */
  408.    /* ::+---------------------------------------+}}|6V ||       |   */
  409.    /* :}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}+---++-------+   */
  410.    /*                                                               */
  411.    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  412.    list = (struct G_LIST *)gad->UserData;
  413.  
  414.    /* We need to figure out how big the NEW and DEL gadgets will be */
  415.    alen = ilen = text_width(global.text[TEXT_NEW]);
  416.    dlen = text_width(global.text[TEXT_DEL]);
  417.    if (dlen > ilen) ilen = dlen;
  418.    ilen += 2*DHBAR;
  419.  
  420.    gad->GadgetText->TopEdge   = -global.ri.FontSize;
  421.    gad->TopEdge     += global.ri.FontSize;
  422.    gad->Width       -= ilen + PROP_WIDTH;
  423.    gad->Height       = global.listsize*global.eheight + global.listextra;
  424.    gad->Flags        = GADGHNONE;
  425.    gad->GadgetRender = build_border(gad->Width,
  426.                                     gad->Height,
  427.                                     MODE_OUT);
  428.  
  429.    savetitle = list->base.title;
  430.    list->base.title = "";
  431.  
  432.    uly = gad->TopEdge;
  433.    ulx = gad->LeftEdge + gad->Width;
  434.  
  435.    /* Create the slider and two arrow gadgets.  We will steal the  */
  436.    /* first itext structure and throw it on to the main gadget     */
  437.    slider = create_gadget(gadlist, (struct G_OBJECT *)list,
  438.                                   ulx+DVBAR, uly+DHBAR, PROP_WIDTH-2*DVBAR );
  439.    if (slider == NULL) return(0);
  440.    list->slider = slider;
  441.    slider->Height       = global.listextra + global.listsize*global.eheight -
  442.                           2*ARR_HEIGHT - 2*DHBAR;
  443.    slider->GadgetID     = CLASS_PROP;
  444.    slider->GadgetType   = PROPGADGET;
  445.    slider->Activation |= (GACT_IMMEDIATE | GACT_RELVERIFY | GACT_FOLLOWMOUSE);
  446.    pi = (struct PropInfo *)get_mem(sizeof(struct PropInfo)+
  447.                                            sizeof(struct Image));
  448.    if (pi == NULL) return(0);
  449.    slider->GadgetRender = (struct Image *)(pi+1);
  450.    slider->SpecialInfo  = (APTR)pi;
  451.    pi->Flags = AUTOKNOB | FREEVERT | PROPBORDERLESS;
  452.    recalc_prop(list, &pi->VertBody, &pi->VertPot);
  453.  
  454.    upgad  = create_gadget(gadlist, (struct G_OBJECT *)list,
  455.                                   ulx, uly+slider->Height+2*DHBAR, PROP_WIDTH);
  456.    if (upgad == NULL) return(0);
  457.    upgad->Height       = ARR_HEIGHT;
  458.    upgad->GadgetRender = &global.arrowborder[1];
  459.    upgad->GadgetID     = CLASS_UP;
  460.    upgad->GadgetText   = NULL;
  461.  
  462.    dngad  = create_gadget(gadlist, (struct G_OBJECT *)list,
  463.                                   ulx, upgad->TopEdge+ARR_HEIGHT, PROP_WIDTH);
  464.    if (dngad == NULL) return(0);
  465.    dngad->Height       = ARR_HEIGHT;
  466.    dngad->GadgetRender = &global.arrowborder[0];
  467.    dngad->GadgetID     = CLASS_DOWN;
  468.    dngad->GadgetText   = NULL;
  469.  
  470.    /* Create the ADD/DEL Buttons                                              */
  471.    addgad = create_gadget(gadlist, (struct G_OBJECT *)list, ulx+PROP_WIDTH,
  472.                                   uly + global.listextra + global.listsize*global.eheight-2*global.iheight, ilen);
  473.    if (addgad == NULL) return(0);
  474.    addgad->GadgetRender = build_border(ilen, addgad->Height, MODE_OUT);
  475.    addgad->GadgetID     = CLASS_ADD;
  476.    addgad->GadgetText->LeftEdge += (ilen-alen)>>1;
  477.    addgad->GadgetText->IText = global.text[TEXT_NEW];
  478.  
  479.    delgad = create_gadget(gadlist, (struct G_OBJECT *)list, addgad->LeftEdge,
  480.                                        addgad->TopEdge+addgad->Height, ilen);
  481.    if (delgad == NULL) return(0);
  482.    list->delgad = delgad;
  483.    delgad->GadgetRender = addgad->GadgetRender;
  484.    delgad->GadgetID     = CLASS_DEL;
  485.    if (list->first == NULL)
  486.       delgad->Flags       |= GADGDISABLED;
  487.    delgad->GadgetText->LeftEdge += (ilen-dlen)>>1;
  488.    delgad->GadgetText->IText = global.text[TEXT_DEL];
  489.  
  490.    for(i = 0; i < global.listsize; i++)
  491.    {
  492.       struct Gadget *tgad;
  493.  
  494.       /* Create the string and button gadgets.  Because we insert them on the */
  495.       /* List in reverse order and we want the button gadget to appear first, */
  496.       /* we need to create them in reverse order.                             */
  497.       /* This ordering is assumed in the state changing code.                 */
  498.       tgad = list->strgad[i] = create_gadget(gadlist,
  499.                                              (struct G_OBJECT *)list,
  500.                                              gad->LeftEdge+VBAR, uly,
  501.                                              gad->Width-DVBAR);
  502.       if (tgad == NULL) return(0);
  503.       tgad->GadgetText = NULL;
  504.       tgad->Height = global.eheight;
  505. /* is this appropriate??? */
  506.       tgad->GadgetID   = CLASS_LIST+(i<<SUBCLASS_OFF);
  507.       setup_string_gadget(tgad, CLASS_LIST);
  508.  
  509.       tgad = list->btngad[i] = create_gadget(gadlist,
  510.                                              (struct G_OBJECT *)list,
  511.                                              gad->LeftEdge+VBAR, uly,
  512.                                              gad->Width-DVBAR);
  513.       if (tgad == NULL) return(0);
  514.       tgad->Height     = global.eheight;
  515.       tgad->GadgetText = NULL;
  516.       tgad->GadgetID   = CLASS_LIST+(i<<SUBCLASS_OFF);
  517.       uly += global.eheight;
  518.    }
  519.  
  520.    list->sborder = list->strgad[0]->GadgetRender;
  521.    list->strgad[0]->GadgetRender = NULL;
  522.  
  523.    /* Undo the damage we did to the base object */
  524.    list->base.title = savetitle;
  525.    list->base.gadget = gad;
  526.  
  527.    reset_list_object(list, -1);
  528.  
  529.    return(uly+global.listextra);
  530. }
  531.  
  532. /***********************************************************************************
  533.  * Procedure: layout_gadgets
  534.  * Synopsis:  gadlist = layout_gadgets(objlist, ulx, yly, width);
  535.  * Purpose:   Create all the appropriate gadgetry and image structures for a list
  536.  *            of gadgets.
  537.  ***********************************************************************************/
  538. struct GADLIST *layout_gadgets(struct G_OBJECT *objlist,
  539.                                int ulx, int uly,
  540.                                int width
  541.                               )
  542. {
  543.    struct Gadget *gad;
  544.    struct IntuiText *itext, *itext1;
  545.    int ilen;
  546.    struct G_OBJECT *obj;
  547.    struct GADLIST *gadlist;
  548.  
  549.    if (create_borders()) return(NULL);
  550.  
  551.    gadlist = (struct GADLIST *)get_mem(sizeof(struct GADLIST));
  552.    if (gadlist == NULL) return(NULL);
  553.  
  554.    /* First we need to lay out the gadgets on the left side of the window */
  555.    for(obj = objlist; obj != NULL; obj = obj->next)
  556.    {
  557.       /* Make sure that the gadget will fit on the screen.  We don't even pretend */
  558.       /* To handle the case of a list gadget going over                           */
  559.       if (uly > (global.height - global.ri.WindowBottom - 2*global.iheight))
  560.          return(gadlist);
  561.  
  562.       /* Create a gadget structure and an associated intuitext structure to be */
  563.       /* Layed out on the screen                                               */
  564.       gad = create_gadget(gadlist, obj, ulx, uly, width);
  565.  
  566.       if (gad == NULL) return(gadlist);
  567.  
  568.       itext = (struct IntuiText *)(gad+1);
  569.  
  570.       uly += gad->Height;
  571.  
  572.       ilen = IntuiTextLength(itext);
  573.       switch(obj->class)
  574.       {
  575.          case CLASS_STRING:
  576.             gad->LeftEdge   += global.titsize;
  577.             gad->Width       = global.cycsize;
  578.             itext->LeftEdge  = -ilen;
  579.             setup_string_gadget(gad, CLASS_STRING);
  580.             break;
  581.  
  582.          case CLASS_CYCLE:
  583.             gad->GadgetRender = global.cycborder;
  584.             gad->GadgetType = BOOLGADGET;
  585.             gad->LeftEdge   += global.titsize;
  586.             gad->Width       = global.cycsize;
  587.             itext->LeftEdge  = -ilen;
  588.             itext1 = (struct IntuiText *)get_mem(sizeof(struct IntuiText));
  589.             if (itext1 == NULL) return(gadlist);
  590.             itext1->FrontPen  = 1;
  591.             itext1->BackPen   = 0;
  592.             itext1->DrawMode  = JAM1;
  593.             itext1->LeftEdge  = 0;
  594.             itext1->TopEdge   = 3;
  595.             itext1->ITextFont = &global.ri.TextAttr;
  596.             itext1->IText     = ((struct G_CYCLE *)obj)->curval->title;
  597.             itext1->NextText  = NULL;
  598.             itext1->LeftEdge  = (CYC_ICON_WIDTH+gad->Width-IntuiTextLength(itext1))/2;
  599.  
  600.             itext->NextText   = itext1;
  601.             itext1->IText     = ((struct G_CYCLE *)obj)->curval->title;
  602.             break;
  603.  
  604.          case CLASS_CHECK:
  605.             gad->GadgetType   = BOOLGADGET;
  606.             gad->Width        = CHECK_WIDTH;
  607.             gad->Height       = CHECK_HEIGHT;
  608.             gad->Flags        = GADGHIMAGE;
  609.             if (obj->state & STATE_MASK)   gad->Flags |= SELECTED;
  610.             gad->Activation  |= TOGGLESELECT;
  611.             gad->GadgetRender = global.checkborder[0];
  612.             gad->SelectRender = global.checkborder[1];
  613.             itext->LeftEdge  += CHECK_WIDTH + 4;
  614.             break;
  615.  
  616.          case CLASS_LIST:
  617.             uly = setup_list_object(gadlist, gad);
  618.             if (uly <= 0) return(gadlist);
  619.             break;
  620.  
  621.          default:
  622.             gad->GadgetType = BOOLGADGET;
  623.             break;
  624.       }
  625.    }
  626.    return(gadlist);
  627. }
  628.  
  629. /***********************************************************************************
  630.  * Procedure: build_border
  631.  * Synopsis:  Border = build_border(width, height, mode)
  632.  * Purpose:   Build an return a set of drawing vectors that represent a button of
  633.  *            width and height.  Mode can be either MODE_OUT or MODE_IN
  634.  ***********************************************************************************/
  635. struct Border *build_border(int width,
  636.                             int height,
  637.                             int mode
  638.                            )
  639. {
  640.    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  641.    /*                                                                             */
  642.    /* Select the colors based on the rendering mode.  For an out box, we will use */
  643.    /* the lighter color on the upper and left sides and the darker color on the   */
  644.    /* other two sides.  In an in box, the choice is reversed.                     */
  645.    /*   (x,y)                                                5                    */
  646.    /*   1****************************************************.2                   */
  647.    /*    **4                                               3..                    */
  648.    /*    **                                                 ..                    */
  649.    /*    **                                                 ..                    */
  650.    /*    **                                                 ..                    */
  651.    /*    **                                                 ..                    */
  652.    /*    **3 5                                             4..                    */
  653.    /*   2*....................................................1                   */
  654.    /*                                                       (x+width, y+height)   */
  655.    /* 0.       0,    0    10.   wd,   ht                                          */
  656.    /* 2.       0,   ht    12.   wd,    0                                          */
  657.    /* 4.       1, ht-1    14. wd-1,    1                                          */
  658.    /* 6.       1,    0    16. wd-1,   ht                                          */
  659.    /* 8.    wd-1,    0    18.    1,   ht                                          */
  660.    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  661.  
  662.    struct Border *border, *border1;
  663.    short *vecs;
  664.    int i;
  665.  
  666.    static short inits[] = { 0, 0,   0, 0,   1,-1,   1, 0,  -1, 0,
  667.                             0, 0,   0, 0,  -1, 1,  -1, 0,   1, 0};
  668.  
  669. #define VEC_COUNT 5
  670. #define SINGLEUNIT (sizeof(struct Border)+sizeof(inits))
  671.  
  672.    width--;
  673.    height--;
  674.    border = (struct Border *)get_mem(2*SINGLEUNIT);
  675.    if (border == NULL) return(NULL);
  676.  
  677.    border1 = border+1;
  678.    vecs = (short *)(border+2);
  679.    border->NextBorder = border1;
  680.    border->DrawMode   = JAM1;
  681.    border->Count      = VEC_COUNT;
  682.    border->XY         = vecs;
  683.  
  684.    border1->DrawMode  = JAM1;
  685.    border1->Count     = VEC_COUNT;
  686.    border1->XY        = vecs + (2*VEC_COUNT);
  687.  
  688.    memcpy((char *)vecs, (char *)inits, sizeof(inits));
  689.    for(i = 8; i < 17; i += 2) vecs[i] += width;
  690.    vecs[3]  += height;
  691.    vecs[5]  += height;
  692.    vecs[11] += height;
  693.    vecs[17] += height;
  694.    vecs[19] += height;
  695.  
  696.    if (mode == MODE_OUT)
  697.    {
  698.       border1->FrontPen = global.ri.Shadow;
  699.       border->FrontPen = global.ri.Highlight;
  700.    }
  701.    else
  702.    {
  703.       border1->FrontPen = global.ri.Highlight;
  704.       border->FrontPen  = global.ri.Shadow;
  705.    }
  706.    return(border);
  707. }
  708.  
  709. /***********************************************************************************
  710.  * Procedure: init_gad_sizes
  711.  * Synopsis:  rc = init_gad_sizes(swidth, sheight, resize);
  712.  * Purpose:   Calculate and initialize all the imagery structures
  713.  ***********************************************************************************/
  714. int init_gad_sizes(int swidth,
  715.                    int sheight,
  716.                    int resize)
  717. {
  718.    int i;
  719.    int width, height, wextra, wmarg;
  720.    static int savewidth, saveheight;
  721.  
  722.    wmarg = MARGIN_LEFT + MARGIN_RIGHT;
  723.    if (!resize)          /* not resizing                */
  724.       if (savewidth)     /* and we already have a size  */
  725.          if ((savewidth < swidth) && (saveheight < sheight))
  726.          {               /* and it will fit this screen */
  727.             swidth = savewidth;
  728.             sheight = saveheight;
  729.             resize = 1;  /* trust me...                 */
  730.          }
  731.  
  732.    wmarg += RESIZE_WIDTH + MARGIN_LEFT;
  733.  
  734.    global.listsize = 0;
  735.    /* Make two passes attempting to layout the items.  The first time we will use */
  736.    /* Whatever the prevailing font is.  If this doesn't work, we will switch to a */
  737.    /* Simple TOPAZ80 and try again.  Only if that fails will we give up.          */
  738.    for(i = 5; i >= 0; i--)
  739.    {
  740.       global.iheight = global.ri.TextAttr.ta_YSize+DHBAR;
  741. /* debug - why not try believing TextAttr ? */
  742. /*
  743.       if (global.iheight < global.ri.FontSize)
  744.          global.iheight = global.ri.FontSize;
  745. */
  746.       if (global.iheight < global.ri.FontSize)
  747.          global.ri.FontSize = global.iheight;
  748.  
  749.       if (i)
  750.       {
  751.          global.iheight += 4; /* Account for decent margins on the rendering */
  752.          global.eheight = global.ri.FontSize + 2*DHBAR;
  753.          global.listextra = 0;
  754.       }
  755.       else
  756.       {
  757.          global.iheight += 2; /* Account for decent margins on the rendering */
  758.          global.eheight = global.ri.FontSize + DHBAR + HBAR;
  759.          global.listextra = 1;
  760.       }
  761.  
  762.       /* We have the totals for everything, let's figure out how */
  763.       /* big the final thing is going to be.                     */
  764.       height = recalc_group_sizes(global.objects, &global.titsize, &global.cycsize)+
  765.                global.iheight + MARGIN_MID +  /* Gadgets on the bottom */
  766.                global.ri.WindowTitle + global.ri.WindowBottom;
  767.  
  768.       width  = global.cycsize + global.titsize + wmarg;           
  769.  
  770.       if ((wextra = (width - swidth)) > 0)
  771.          {
  772.          if (wextra < global.titsize)
  773.             global.titsize -= wextra;
  774.          else
  775.              global.titsize = 0;
  776.          }
  777.  
  778.       if ((i == 5) && (height <= sheight))
  779.       {
  780.          int num;
  781.          num = (sheight - height) / global.eheight;
  782.          if (num < 3)
  783.          {
  784.             height = sheight + 1; /* Force a failure */
  785.          }
  786.          else
  787.          {
  788.             if (!resize) /* first time in go for medium size */
  789.             {
  790.                if (num > 10) num = 10;
  791.             }
  792.             else
  793.                if (num > MAX_LIST) num = MAX_LIST;
  794.             global.listsize = num;
  795.             height += num*global.eheight;
  796.          }
  797.       }
  798.  
  799.       if (height <= sheight) break;
  800.       /* can we do anything here about insufficient width ? */
  801.  
  802.       switch(i)
  803.       {
  804.          case 0:
  805.             break;
  806.          case 1:
  807.          case 2:
  808.             /* Set up so we try with Topaz 80 as our default font the second time around */
  809.             global.ri.TextAttr = TOPAZ80;
  810.             break;
  811.          case 5:
  812.             global.listsize = 9;
  813.             break;
  814.          default:
  815.             global.listsize = (global.listsize / 2) + 1;
  816.             if (global.listsize < 3) global.listsize = 3;
  817.             break;
  818.       }
  819.    }
  820.  
  821.    /* Everything worked out fine, let us set the height of the window */
  822.    global.width = resize ? swidth : width;
  823.    global.height = resize ? sheight : height;
  824.    savewidth = global.width;
  825.    saveheight = global.height;
  826.  
  827.    /* Also see if we need to adjust the titsize and cycsize values */
  828.    i = global.width - width;
  829.    if (i > 0)
  830.       global.cycsize += i;
  831.  
  832.    return(0);
  833. }
  834.  
  835.  
  836. /***********************************************************************************
  837.  * Procedure: create_borders
  838.  * Synopsis:  create_borders
  839.  * Purpose:   Create the borders for all the gadgets
  840.  ***********************************************************************************/
  841. int create_borders()
  842. {
  843.    struct Border *border;
  844.    /* * * * * * * * * * * * * * * * * * * * * * * * * * */
  845.    /*                                                   */
  846.    /*              11111111                11111111     */
  847.    /*    012345678901234567      012345678901234567     */
  848.    /*    =================#      =================# 0   */
  849.    /*    ||......23......##      ||..18......54..## 1   */
  850.    /*    ||......##......##      ||..##......##..## 2   */
  851.    /*    ||.....####.....##      ||...##....##...## 3   */
  852.    /*    ||....##76##....##      ||....##76##....## 4   */
  853.    /*    ||...##....##...##      ||.....####.....## 5   */
  854.    /*    ||..##......##..##      ||......##......## 6   */
  855.    /*    ||..18......54..##      ||......23......## 7   */
  856.    /*    |#################      |################# 8   */
  857.    /*                                                   */
  858.    /* * * * * * * * * * * * * * * * * * * * * * * * * * */
  859.    static short Up_Vectors[] = { 4,6,  8,2,  9,2, 13,6, 12,6,  9,3,  8,3,  5,6 };
  860.    static short Dn_Vectors[] = { 4,2,  8,6,  9,6, 13,2, 12,2,  9,5,  8,5,  5,2 };
  861.  
  862.    /* * * * * * * * * * * * * * * * * * */
  863.    /*              11111111112222       */
  864.    /*    012345678901234567890134       */
  865.    /*    ========================== 0   */
  866.    /*    ||.....7.....8..........   1   */
  867.    /*    ||.....#######......#|..   2   */
  868.    /*    ||...5##.....##d....#|..   3   */
  869.    /*    ||....##.....##.....#|..   4   */
  870.    /*    ||....##..a######b..#|..   5   */
  871.    /*    ||....##....####....#|..   6   */
  872.    /*    ||....##....9##c....#|..   7   */
  873.    /*    ||....##............#|..   8   */
  874.    /*    ||...4##6...0##1....#|..   9   */
  875.    /*    ||.....#######......#|..   10  */
  876.    /*    ||.....3.....2..........   11  */
  877.    /*    |########################  12  */
  878.    /*                                   */
  879.    /* * * * * * * * * * * * * * * * * * */
  880.    static short Cycle_Vectors[] = { 13, 9,  14, 9,  13,10,   7,10,   6, 9,
  881.                                      6, 3,   7, 9,   7, 2,  13, 2,  13, 7,
  882.                                     11, 5,  16, 5,  14, 7,  14, 3, };
  883.    static short Cycle_Line1[]   = { 20, 2,  20,11};
  884.    static short Cycle_Line2[]   = { 21, 2,  21,11};
  885.  
  886.    static short Check_Vectors[] = { 19, 2,  17, 2,  11, 8,   8, 5,   7, 5,
  887.                                     10, 8,   9, 5,  12, 8,  18, 2 };
  888.  
  889.    /* Now we have calculated sizes for the objects, layout the border structures */
  890.  
  891.    /* Create a border for the cycle gadgets */
  892.    global.cycborder = build_border(global.cycsize,
  893.                                        global.iheight, MODE_OUT);
  894.    /* We also need to put in the vectors for the cycle picture */
  895.    border = (struct Border *)get_mem(5*sizeof(struct Border));
  896.    if (border == NULL) return(1);
  897.  
  898.    border[0].NextBorder = border+1;
  899.    border[1].NextBorder = border+2;
  900.    border[2].NextBorder = global.cycborder;
  901.    global.cycborder = border;
  902.  
  903.    border[0].DrawMode = JAM1;
  904.    border[0].Count  = sizeof(Cycle_Vectors)/(2*sizeof(short));
  905.    border[0].XY = Cycle_Vectors;
  906.    border[0].FrontPen = 1;
  907.  
  908.    border[1].DrawMode = JAM1;
  909.    border[1].Count  = sizeof(Cycle_Line1)/(2*sizeof(short));
  910.    border[1].XY = Cycle_Line1;
  911.    border[1].FrontPen = global.ri.Shadow;
  912.  
  913.    border[2].DrawMode = JAM1;
  914.    border[2].Count  = sizeof(Cycle_Line2)/(2*sizeof(short));
  915.    border[2].XY = Cycle_Line2;
  916.    border[2].FrontPen = global.ri.Highlight;
  917.  
  918.    global.checkborder[0] = border+3;
  919.    border[3].NextBorder = build_border(CHECK_WIDTH, CHECK_HEIGHT, MODE_OUT);
  920.    border[3].DrawMode = JAM1;
  921.    border[3].Count = sizeof(Check_Vectors)/(2*sizeof(short));
  922.    border[3].XY = Check_Vectors;
  923.    border[3].FrontPen = 0;
  924.  
  925.    global.checkborder[1] = border+4;
  926.    border[4].NextBorder = build_border(CHECK_WIDTH, CHECK_HEIGHT, MODE_OUT);
  927.    border[4].DrawMode = JAM1;
  928.    border[4].Count = sizeof(Check_Vectors)/(2*sizeof(short));
  929.    border[4].XY = Check_Vectors;
  930.    border[4].FrontPen = 1;
  931.  
  932.    /* Adjust the height of the cycle vectors to the current height */
  933.    /* See the picture above for these values.  Yes, they are hard  */
  934.    /* coded magic values, but equates for them don't make a lot of */
  935.    /* sense in a situation like this.                              */
  936.    {
  937.       int cheight;
  938.       if (global.iheight > 11)
  939.          cheight = global.iheight;
  940.       else
  941.          cheight = 11;
  942.       cheight -= DHBAR;
  943.       Cycle_Vectors[1] = cheight - 2;
  944.       Cycle_Vectors[3] = cheight - 2;
  945.       Cycle_Vectors[5] = cheight - 1;
  946.       Cycle_Vectors[7] = cheight - 1;
  947.       Cycle_Vectors[9] = cheight - 2;
  948.       Cycle_Vectors[13] = cheight - 2;
  949.    }
  950. /*
  951.    for(i = 0; i < 0x0d; i++)
  952.    {
  953.       int extra;
  954.  
  955.       extra = global.iheight - 13;
  956.       if (i > 8)
  957.       {
  958.          extra >>= 1;
  959.       }
  960.       else if ((i > 6) || (i == 5))
  961.       {
  962.          extra = 0;
  963.       }
  964.  
  965.       Cycle_Vectors[1+i*2] += extra;
  966.    }
  967. */
  968.  
  969.    Cycle_Line2[3] = Cycle_Line1[3] = (global.iheight - 1) - DHBAR;
  970.  
  971.    {
  972.       int bheight;
  973.       bheight = (global.listsize*global.eheight) - (2*ARR_HEIGHT) + global.listextra;
  974.       border = build_border(PROP_WIDTH, bheight, MODE_OUT);
  975.       if (border == NULL) return(1);
  976.  
  977.       border->TopEdge -= bheight;
  978.       border->NextBorder->TopEdge -= bheight;
  979.    }
  980.  
  981.    global.arrowborder[0].NextBorder = build_border(PROP_WIDTH, ARR_HEIGHT, MODE_OUT);
  982.    global.arrowborder[1].NextBorder = border;
  983.    border->NextBorder->NextBorder = global.arrowborder[0].NextBorder;
  984.  
  985.    global.arrowborder[0].DrawMode = JAM1;
  986.    global.arrowborder[0].Count  = sizeof(Dn_Vectors)/(2*sizeof(short));
  987.    global.arrowborder[0].XY = Dn_Vectors;
  988.    global.arrowborder[0].FrontPen = 1;
  989.  
  990.    global.arrowborder[1].DrawMode = JAM1;
  991.    global.arrowborder[1].Count  = sizeof(Up_Vectors)/(2*sizeof(short));
  992.    global.arrowborder[1].XY = Up_Vectors;
  993.    global.arrowborder[1].FrontPen = 1;
  994.    return(0);
  995. }
  996.  
  997. /***********************************************************************************
  998.  * Procedure: recalc_group_sizes
  999.  * Synopsis:  recalc_group_sizes(objlist, &titsize, &cycsize)
  1000.  * Purpose:   Calculate the base sizes for different types of objects.
  1001.  *            We need to calculate the width for CYCLE titles and size for cycles
  1002.  *            Everything else has a fixed size to be used anyway.
  1003.  ***********************************************************************************/
  1004. int recalc_group_sizes(struct G_OBJECT *objlist,
  1005.                     int *titsize,
  1006.                     int *cycsize)
  1007. {
  1008.    int wid;
  1009.    int height;
  1010.    struct G_OBJECT *obj;
  1011.    struct G_CYCLE *cyc;
  1012.    struct G_VALUE *val;
  1013.  
  1014.    *titsize = 0;
  1015.    *cycsize = 0;
  1016.    height = 0;
  1017.  
  1018.    /* First we need to lay out the gadgets on the left side of the window */
  1019.    for(obj = objlist; obj != NULL; obj = obj->next)
  1020.    {
  1021.       switch(obj->class)
  1022.       {
  1023.          case CLASS_CYCLE:
  1024.             /* go through and get all the cycle values */
  1025.             cyc = (struct G_CYCLE *)obj;
  1026.             set_cyc_state(cyc, cyc->curval);
  1027.             for(val = cyc->values; val != NULL; val = val->next)
  1028.             {
  1029.                wid = text_width(val->title);
  1030.                if (val->string)
  1031.                {
  1032.                   char *p;
  1033.                   int num;
  1034.  
  1035.                   p = strchr(val->option, '%');
  1036.                   num = 0;
  1037.                   if (p)
  1038.                   {
  1039.                      p++;
  1040.                      while ((*p >= '0') && (*p <= '9'))
  1041.                         num = (num * 10) + *p++ - '0';
  1042.                   }
  1043.                   if (num <= 0) num = 3;
  1044.                      wid += (text_width("0") * (num+1)) + DVBAR;
  1045.                }
  1046.                if (wid > *cycsize) *cycsize = wid;
  1047.             }
  1048.             /* Fall through and get the title size */
  1049.          case CLASS_STRING:
  1050.             wid = text_width(obj->title);
  1051.             if (wid > *titsize) *titsize = wid;
  1052.             break;
  1053.          case CLASS_LIST:
  1054.             height += global.eheight * global.listsize;
  1055.             break;
  1056.          case CLASS_CHECK:
  1057.             break;
  1058.          default:
  1059.             printf("Huh\n");
  1060.             break;
  1061.       }
  1062.       height += global.iheight;
  1063.    }
  1064.    *titsize += DVBAR;
  1065.    *cycsize += CYC_ICON_WIDTH+DVBAR;
  1066.  
  1067.    return(height);
  1068. }
  1069.  
  1070. /***********************************************************************************
  1071.  * Procedure: text_width
  1072.  * Synopsis:  len = text_width(str)
  1073.  * Purpose:   Return the rendered width of a given string
  1074.  ***********************************************************************************/
  1075. int text_width(char *str
  1076.               )
  1077. {
  1078.    struct IntuiText itext;
  1079.  
  1080.    itext.FrontPen  = 1;
  1081.    itext.BackPen   = 0;
  1082.    itext.DrawMode  = JAM1;
  1083.    itext.LeftEdge  = 0;
  1084.    itext.TopEdge   = 1;
  1085.    itext.ITextFont = &global.ri.TextAttr;
  1086.    itext.NextText  = NULL;
  1087.    itext.IText     = str;
  1088.  
  1089.    return(IntuiTextLength(&itext));
  1090. }
  1091.